﻿using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MKAdminCore.ToolKit.RedisHelper
{

    /// <summary>
    /// Set：用哈希表来保持字符串的唯一性，没有先后顺序，存储一些集合性的数据
    /// 1.共同好友、二度好友
    /// 2.利用唯一性，可以统计访问网站的所有独立 IP
    /// </summary>
    public class RedisSetHelper
    {
        #region 构造函数

        /// <summary>
        /// 初始化Redis的Set无序数据结构操作
        /// </summary>
        /// <param name="dbNum">操作的数据库索引0-64(需要在conf文件中配置)</param>
        static RedisSetHelper()
        {
            RedisManager.CreateConn();
        }
        #endregion

        #region 同步方法
        /// <summary>
        /// 在Key集合中添加一个value值
        /// </summary>
        /// <typeparam name="T">数据类型</typeparam>
        /// <param name="key">Key名称</param>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static bool Set<T>(string key, T value)
        {
            string jValue = RedisManager.ConvertJson(value);
            return RedisManager.redis.SetAdd(key, jValue);
        }
        /// <summary>
        /// 在Key集合中添加多个value值
        /// </summary>
        /// <typeparam name="T">数据类型</typeparam>
        /// <param name="key">Key名称</param>
        /// <param name="value">值列表</param>
        /// <returns></returns>
        public static long Set<T>(string key, List<T> value)
        {
            RedisValue[] valueList = RedisManager.ConvertRedisValue(value.ToArray());
            return RedisManager.redis.SetAdd(key, valueList);
        }

        /// <summary>
        /// 获取key集合值的数量
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static long GetLength(string key)
        {
            return RedisManager.redis.SetLength(key);
        }

        /// <summary>
        /// 判断Key集合中是否包含指定的值
        /// </summary>
        /// <typeparam name="T">值类型</typeparam>
        /// <param name="key"></param>
        /// <param name="value">要判断是值</param>
        /// <returns></returns>
        public static bool Contains<T>(string key, T value)
        {
            string jValue = RedisManager.ConvertJson(value);
            return RedisManager.redis.SetContains(key, jValue);
        }

        /// <summary>
        /// 随机获取key集合中的一个值
        /// </summary>
        /// <typeparam name="T">数据类型</typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public static T RandomMember<T>(string key)
        {
            var rValue = RedisManager.redis.SetRandomMember(key);
            return RedisManager.ConvertObj<T>(rValue);
        }

        /// <summary>
        /// 获取key所有值的集合
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public static List<T> Members<T>(string key)
        {
            var rValue = RedisManager.redis.SetMembers(key);
            return RedisManager.ConvetList<T>(rValue);
        }

        /// <summary>
        /// 删除key集合中指定的value
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static long Remove<T>(string key, params T[] value)
        {
            RedisValue[] valueList = RedisManager.ConvertRedisValue(value);
            return RedisManager.redis.SetRemove(key, valueList);
        }

        /// <summary>
        /// 随机删除key集合中的一个值，并返回该值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public static T Pop<T>(string key)
        {
            var rValue = RedisManager.redis.SetPop(key);
            return RedisManager.ConvertObj<T>(rValue);
        }


        /// <summary>
        /// 获取几个集合的并集
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="keys">要操作的Key集合</param>
        /// <returns></returns>
        public static List<T> CombineUnion<T>(params string[] keys)
        {
            return _SetCombine<T>(SetOperation.Union, keys);
        }
        /// <summary>
        /// 获取几个集合的交集
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="keys">要操作的Key集合</param>
        /// <returns></returns>
        public static List<T> CombineIntersect<T>(params string[] keys)
        {
            return _SetCombine<T>(SetOperation.Intersect, keys);
        }
        /// <summary>
        /// 获取几个集合的差集
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="keys">要操作的Key集合</param>
        /// <returns></returns>
        public static List<T> CombineDifference<T>(params string[] keys)
        {
            return _SetCombine<T>(SetOperation.Difference, keys);
        }

        /// <summary>
        /// 获取几个集合的并集,并保存到一个新Key中
        /// </summary>
        /// <param name="destination">保存的新Key名称</param>
        /// <param name="keys">要操作的Key集合</param>
        /// <returns></returns>
        public static long CombineUnionAndStore(string destination, params string[] keys)
        {
            return _SetCombineAndStore(SetOperation.Union, destination, keys);
        }
        /// <summary>
        /// 获取几个集合的交集,并保存到一个新Key中
        /// </summary>
        /// <param name="destination">保存的新Key名称</param>
        /// <param name="keys">要操作的Key集合</param>
        /// <returns></returns>
        public static long CombineIntersectAndStore(string destination, params string[] keys)
        {
            return _SetCombineAndStore(SetOperation.Intersect, destination, keys);
        }
        /// <summary>
        /// 获取几个集合的差集,并保存到一个新Key中
        /// </summary>
        /// <param name="destination">保存的新Key名称</param>
        /// <param name="keys">要操作的Key集合</param>
        /// <returns></returns>
        public static long CombineDifferenceAndStore(string destination, params string[] keys)
        {
            return _SetCombineAndStore(SetOperation.Difference, destination, keys);
        }
        #endregion

        #region 异步方法
        /// <summary>
        /// 在Key集合中添加一个value值
        /// </summary>
        /// <typeparam name="T">数据类型</typeparam>
        /// <param name="key">Key名称</param>
        /// <param name="value">值</param>
        /// <returns></returns>
        public async static Task<bool> SetAsync<T>(string key, T value)
        {
            string jValue = RedisManager.ConvertJson(value);
            return await RedisManager.redis.SetAddAsync(key, jValue);
        }
        /// <summary>
        /// 在Key集合中添加多个value值
        /// </summary>
        /// <typeparam name="T">数据类型</typeparam>
        /// <param name="key">Key名称</param>
        /// <param name="value">值列表</param>
        /// <returns></returns>
        public async static Task<long> SetAsync<T>(string key, List<T> value)
        {
            RedisValue[] valueList = RedisManager.ConvertRedisValue(value.ToArray());
            return await RedisManager.redis.SetAddAsync(key, valueList);
        }

        /// <summary>
        /// 获取key集合值的数量
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async static Task<long> GetLengthAsync(string key)
        {
            return await RedisManager.redis.SetLengthAsync(key);
        }

        /// <summary>
        /// 判断Key集合中是否包含指定的值
        /// </summary>
        /// <typeparam name="T">值类型</typeparam>
        /// <param name="key"></param>
        /// <param name="value">要判断是值</param>
        /// <returns></returns>
        public async static Task<bool> ContainsAsync<T>(string key, T value)
        {
            string jValue = RedisManager.ConvertJson(value);
            return await RedisManager.redis.SetContainsAsync(key, jValue);
        }

        /// <summary>
        /// 随机获取key集合中的一个值
        /// </summary>
        /// <typeparam name="T">数据类型</typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public async static Task<T> RandomMemberAsync<T>(string key)
        {
            var rValue = await RedisManager.redis.SetRandomMemberAsync(key);
            return RedisManager.ConvertObj<T>(rValue);
        }

        /// <summary>
        /// 获取key所有值的集合
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public async static Task<List<T>> MembersAsync<T>(string key)
        {
            var rValue = await RedisManager.redis.SetMembersAsync(key);
            return RedisManager.ConvetList<T>(rValue);
        }

        /// <summary>
        /// 删除key集合中指定的value
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public async static Task<long> RemoveAsync<T>(string key, params T[] value)
        {
            RedisValue[] valueList = RedisManager.ConvertRedisValue(value);
            return await RedisManager.redis.SetRemoveAsync(key, valueList);
        }

        /// <summary>
        /// 随机删除key集合中的一个值，并返回该值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public async static Task<T> PopAsync<T>(string key)
        {
            var rValue = await RedisManager.redis.SetPopAsync(key);
            return RedisManager.ConvertObj<T>(rValue);
        }


        /// <summary>
        /// 获取几个集合的并集
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="keys">要操作的Key集合</param>
        /// <returns></returns>
        public async static Task<List<T>> CombineUnionAsync<T>(params string[] keys)
        {
            return await _SetCombineAsync<T>(SetOperation.Union, keys);
        }
        /// <summary>
        /// 获取几个集合的交集
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="keys">要操作的Key集合</param>
        /// <returns></returns>
        public async static Task<List<T>> CombineIntersectAsync<T>(params string[] keys)
        {
            return await _SetCombineAsync<T>(SetOperation.Intersect, keys);
        }
        /// <summary>
        /// 获取几个集合的差集
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="keys">要操作的Key集合</param>
        /// <returns></returns>
        public async static Task<List<T>> CombineDifferenceAsync<T>(params string[] keys)
        {
            return await _SetCombineAsync<T>(SetOperation.Difference, keys);
        }



        /// <summary>
        /// 获取几个集合的并集,并保存到一个新Key中
        /// </summary>
        /// <param name="destination">保存的新Key名称</param>
        /// <param name="keys">要操作的Key集合</param>
        /// <returns></returns>
        public async static Task<long> CombineUnionAndStoreAsync(string destination, params string[] keys)
        {
            return await _SetCombineAndStoreAsync(SetOperation.Union, destination, keys);
        }
        /// <summary>
        /// 获取几个集合的交集,并保存到一个新Key中
        /// </summary>
        /// <param name="destination">保存的新Key名称</param>
        /// <param name="keys">要操作的Key集合</param>
        /// <returns></returns>
        public async static Task<long> CombineIntersectAndStoreAsync(string destination, params string[] keys)
        {
            return await _SetCombineAndStoreAsync(SetOperation.Intersect, destination, keys);
        }
        /// <summary>
        /// 获取几个集合的差集,并保存到一个新Key中
        /// </summary>
        /// <param name="destination">保存的新Key名称</param>
        /// <param name="keys">要操作的Key集合</param>
        /// <returns></returns>
        public async static Task<long> CombineDifferenceAndStoreAsync(string destination, params string[] keys)
        {
            return await _SetCombineAndStoreAsync(SetOperation.Difference, destination, keys);
        }

        #endregion

        #region 内部辅助方法
        /// <summary>
        /// 获取几个集合的交叉并集合
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="operation">Union：并集  Intersect：交集  Difference：差集  详见 <see cref="SetOperation"/></param>
        /// <param name="keys">要操作的Key集合</param>
        /// <returns></returns>
        private static List<T> _SetCombine<T>(SetOperation operation, params string[] keys)
        {
            RedisKey[] keyList = RedisManager.ConvertRedisKeysAddSysCustomKey(keys);
            var rValue = RedisManager.redis.SetCombine(operation, keyList);
            return RedisManager.ConvetList<T>(rValue);
        }

        /// <summary>
        /// 获取几个集合的交叉并集合,并保存到一个新Key中
        /// </summary>
        /// <param name="operation">Union：并集  Intersect：交集  Difference：差集  详见 <see cref="SetOperation"/></param>
        /// <param name="destination">保存的新Key名称</param>
        /// <param name="keys">要操作的Key集合</param>
        /// <returns></returns>
        private static long _SetCombineAndStore(SetOperation operation, string destination, params string[] keys)
        {
            RedisKey[] keyList = RedisManager.ConvertRedisKeysAddSysCustomKey(keys);
            return RedisManager.redis.SetCombineAndStore(operation, destination, keyList);
        }
        /// <summary>
        /// 获取几个集合的交叉并集合
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="operation">Union：并集  Intersect：交集  Difference：差集  详见 <see cref="SetOperation"/></param>
        /// <param name="keys">要操作的Key集合</param>
        /// <returns></returns>
        private async static Task<List<T>> _SetCombineAsync<T>(SetOperation operation, params string[] keys)
        {
            RedisKey[] keyList = RedisManager.ConvertRedisKeysAddSysCustomKey(keys);
            var rValue = await RedisManager.redis.SetCombineAsync(operation, keyList);
            return RedisManager.ConvetList<T>(rValue);
        }
        /// <summary>
        /// 获取几个集合的交叉并集合,并保存到一个新Key中
        /// </summary>
        /// <param name="operation">Union：并集  Intersect：交集  Difference：差集  详见 <see cref="SetOperation"/></param>
        /// <param name="destination">保存的新Key名称</param>
        /// <param name="keys">要操作的Key集合</param>
        /// <returns></returns>
        private async static Task<long> _SetCombineAndStoreAsync(SetOperation operation, string destination, params string[] keys)
        {
            RedisKey[] keyList = RedisManager.ConvertRedisKeysAddSysCustomKey(keys);
            return await RedisManager.redis.SetCombineAndStoreAsync(operation, destination, keyList);
        }

        #endregion

    }
}
